package com.wgo.precise.client.ui.view.editor.requirementtable;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;

import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;

import com.wgo.precise.client.ui.controller.exceptions.RematoClientException;
import com.wgo.precise.client.ui.model.AbstractPropertySpesification;
import com.wgo.precise.client.ui.model.CategoryWrapper;
import com.wgo.precise.client.ui.model.ClientModelItem;
import com.wgo.precise.client.ui.model.Configuration;
import com.wgo.precise.client.ui.model.NodeChild;
import com.wgo.precise.client.ui.model.NodeParent;
import com.wgo.precise.client.ui.model.PropertySetWrapper;
import com.wgo.precise.client.ui.model.RequirementWrapper;
import com.wgo.precise.client.ui.model.facade.INodeChild;
import com.wgo.precise.client.ui.model.facade.IRequirementTableProvider;
import com.wgo.precise.client.ui.view.editor.history.HistoryColumnProperties;
import com.wgo.precise.client.ui.view.editor.requirementtable.RequirementTableFormPage;
import com.wgo.precise.client.ui.view.facade.IModelTableEditor;


/**
 * 
 * @author Petter L. H. Eide
 * @version $Id: TableContentProvider.java,v 1.2 2006-01-30 21:52:33 petterei Exp $
 */
public class TableContentProvider implements IStructuredContentProvider, IModelTableEditor<ClientModelItem> {

    private TableViewer currentViewer;
    

    /** specifications for RequirementWrapper and NameableWrapper */
    private List<AbstractPropertySpesification> staticSpesifications ;

//    private IRequirementTableProvider<NodeParent,NodeChild> currentInput;

    private List<TableColumn> oldColumns = new ArrayList<TableColumn>();
    
    /**
     * @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object)
     */
    public Object[] getElements(Object inputElement) {
    	if (inputElement instanceof IRequirementTableProvider) {
    		List<INodeChild> rows = new ArrayList<INodeChild>();
    		for (INodeChild child : ((IRequirementTableProvider<NodeParent,NodeChild>)inputElement).getChildren()) {
    			if (child instanceof RequirementWrapper) {
    				((RequirementWrapper)child).verifyProperties();
    				rows.add(child);
    			} /* else { //TODO: add children of subcategories ?
            	if ( IRequirementTableProvider<INodeParent, INodeChild>)
            	for ( Class iClazz : child.getClass().getInterfaces()) {
            		if (iClazz.equals(INodeParent.class)) {  
            			initRows((INodeParent)child, clazz);
            			return;
            		}
            	}
        		throw new RematoClientException(getClass() + ": Not valid type in requirement hierarchy: " + child.getClass());
            }
    			 */
    		}
    		return rows.toArray();
    	}
    	return new Object[0];
    }

    /**
     * @see org.eclipse.jface.viewers.IContentProvider#dispose()
     */
    public void dispose() {
        staticSpesifications = null;
        oldColumns.clear();
        currentViewer = null;
    }

    /**
     * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer, java.lang.Object, java.lang.Object)
     */
    public synchronized void inputChanged(Viewer newViewer, Object oldInput, Object newInput) {
        
        if (newViewer instanceof TableViewer ) {
        	TableViewer viewer = (TableViewer) newViewer ;
            // set viewer
            if (newViewer != this.currentViewer) {
                this.currentViewer = viewer;
            }

            if (newInput instanceof IRequirementTableProvider) {

                IRequirementTableProvider type = (IRequirementTableProvider) newInput;
//                typeSpesifications = type.getUserDefinedTypes(); //TODO: fix interface

                clearTable(viewer);
                setupTable(viewer, getSpesifications((CategoryWrapper)newInput));
                
            } else {
                if ( oldInput != null) {
                    clearTable(viewer);
                }
            }

        } else {
            currentViewer = null;
            throw new RematoClientException("Not a known viewer: " + newViewer.getClass().getSimpleName() + " (Need to be: " + TableViewer.class.getName() + ")");
        }
    }
    
    private List<AbstractPropertySpesification> getSpesifications(CategoryWrapper wrapper) {
        List<AbstractPropertySpesification> specs = new ArrayList<AbstractPropertySpesification>() ;
        if (null == staticSpesifications){
            Configuration conf = Configuration.getInstance();
            staticSpesifications = new ArrayList<AbstractPropertySpesification>();
            staticSpesifications.addAll(conf.getSortedNodeSpesifications());
            staticSpesifications.addAll(RequirementWrapper.getSortedRequirementSpesifications());
        }
        specs.addAll(staticSpesifications);
        for (PropertySetWrapper propertySetWrapper : wrapper.getPropertyDefinitionSets()) {
        	specs.addAll(propertySetWrapper.getPopertyDefinitions());
        }
        return specs;
    }
    
    private void setupTable(final TableViewer viewer , List<AbstractPropertySpesification> specs) {
        int size = specs.size();
        final Table table = viewer.getTable();
        table.setRedraw(true);
        // create new table layout:
        GridData gridData = new GridData(RequirementTableFormPage.REQ_TABLE_GRID_STYLE);
        gridData.minimumHeight = 60 ;
//        gridData.grabExcessVerticalSpace = true;
//        gridData.horizontalSpan = 3;
        table.setLayoutData(gridData);      
                        
        table.setLinesVisible(true);
        table.setHeaderVisible(true);

        TableColumn column;
        String[] columnNames = new String[size];
        CellEditor[] cellEditors = new CellEditor[size];

//    	Listener sortListener = new Listener() {
//    		public void handleEvent(Event e) {
//    			// determine new sort column and direction
//
//    		}
//    	};
//    	column1.addListener(SWT.Selection, sortListener);
//    	column2.addListener(SWT.Selection, sortListener);

        
        
        int i = 0;
        for (AbstractPropertySpesification spec : specs) {
            
            column = new TableColumn(table, SWT.LEFT, i) ;
            column.setText(spec.getLabel());
            column.setWidth(100);
            column.setMoveable(true);


            oldColumns.add(column);

            columnNames[i] = spec.getLabel();
            CellEditor cellEditor = spec.getCellEditor(table);
//            cellEditor.getControl().setEnabled(!spec.isReadOnly());

            cellEditors[i] = cellEditor;

            i++;

                
                
            column.addSelectionListener(new SelectionAdapter() {
                 /**
                 * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
                 */
                @Override
                public void widgetSelected(SelectionEvent e) {
        			TableColumn sortColumn = table.getSortColumn();
        			TableColumn currentColumn = (TableColumn) e.widget;
        			int dir = table.getSortDirection();
        			if (sortColumn == currentColumn) {
        				dir = dir == SWT.UP ? SWT.DOWN : SWT.UP;
        			} else {
        				table.setSortColumn(currentColumn);
        				dir = SWT.UP;
        			}
//                  TableColumnSorter sorter = (TableColumnSorter)viewer.getComparator();
//                  sorter.sort(viewer, viewer.getE)
//                  sorter.setIndex(((TableColumn)e.getSource()).getParent().indexOf((TableColumn)e.getSource()));

//// TODO:        			
////        			// sort the data based on column and direction
////        			final int index = currentColumn == column1 ? 0 : 1;
//        			final int index;
//        			int tempIndex = 0 ;
//        			for (TableColumn tempColumn : viewer.getTable().getColumns()){
//        				if (tempColumn.equals(currentColumn)){
//        					index = tempIndex;
//        					break;
//        				}
//        				tempIndex++;
//        			}
//        			final int direction = dir;
//        			Arrays.sort(viewer.getTable().getItems(), new Comparator<TableItem>() {
//        				public int compare(TableItem arg0, TableItem arg1) {
//							int inverse = 1 ;
//							if (SWT.DOWN == direction){
//								inverse = -1 ;
//							}
//							spec.getPropertyType().getClazz().
//							((RequirementWrapper)arg0.getData()).
////        					int[] a = (int[]) arg0;
////        					int[] b = (int[]) arg1;
////        					if (a[index] == b[index]) return 0;
////        					if (direction == SWT.UP) {
////        						return a[index] < b[index] ? -1 : 1;
////        					}
////        					return a[index] < b[index] ? 1 : -1;
//        					return 0;
//        				}
//        			});
        			// update data displayed in table
        			table.setSortDirection(dir);
        			table.clearAll();
        			viewer.refresh(true);
                }
            });
        }

        viewer.setColumnProperties(columnNames);
        viewer.setCellEditors(cellEditors);
    	table.setSortColumn(oldColumns.get(0));
    	table.setSortDirection(SWT.UP);

        viewer.setCellModifier(new TableCellModifier(specs, columnNames, this));
        viewer.setLabelProvider(new TableLabelProvider(specs));
        viewer.setComparator( new TableColumnSorter(specs, columnNames) );
//        table.redraw();
        viewer.refresh();
//        table.re
    }
    
    private void clearTable(TableViewer viewer) {

        Table table = viewer.getTable();
        
        for (TableColumn column : oldColumns) {
            column.dispose();
        }
        
        oldColumns.clear();

        if (! table.isDisposed()) {
//            table.removeAll();
//            table.clearAll();
        }

////        viewer.resetFilters();
        
//        viewer.refresh();
    	// => eclipse gives nullpointer

    }

    public void addElement(ClientModelItem element) {
    	//TODO
    }

    public void removeElement(ClientModelItem element) {
    	//TODO
    }

    public void updateElement(ClientModelItem element) {
        if (currentViewer != null) {
            currentViewer.refresh(element);
        }
    }

    @Deprecated
	public boolean insertAfter(@SuppressWarnings("unused") ClientModelItem insert, @SuppressWarnings("unused") ClientModelItem after) {
		return false;
	}

    
    
}
